/*
 * 
 * LegendShop 版权所有 2009-2011,并保留所有权利。
 * 
 * 官方网站：http://www.legendesign.net
 */
package com.legendshop.oa.dao.impl;

import com.legendshop.dao.GenericJdbcDao;
import com.legendshop.framework.model.GrantedFunction;
import com.legendshop.framework.model.GrantedFunctionImpl;
import com.legendshop.oa.constants.ApplicationEnum;
import com.legendshop.oa.dao.AdminAuthDao;
import com.legendshop.oa.model.UserEntity;
import com.legendshop.oa.security.PasswordEncoder;
import com.legendshop.oa.security.UserSaltSource;
import com.legendshop.util.AppUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;
import java.util.List;


/**
 * 管理员验证Dao
 */
public class AdminAuthDaoImpl implements AdminAuthDao {

	/** The log. */
	Logger log = LoggerFactory.getLogger(AdminAuthDaoImpl.class);
    
    /** The password encoder. */
    private PasswordEncoder passwordEncoder;
    
    /** The salt source. */
    private UserSaltSource saltSource;
    
	/** The generic jdbc dao. */
	private GenericJdbcDao genericJdbcDao;
	
	/** The Constant sqlForFindAdminUserByName. */
	private static final String sqlForFindAdminUserByName =
			"SELECT u.id, u.name,u.real_name as realName, u.note,u.enabled, u.password,u.active_time as activeTime, u.pass_change_date AS passChangeDate, u.change_pass AS changePass FROM ls_admin_user u where  u.enabled = '1' and u.name =  ?";
	
	
	/** The Constant sqlForFindFunctionsByUser. */
	private static final  String sqlForFindFunctionsByUser = "select DISTINCT f.protect_function as name from ls_usr_role ur ,ls_role r,ls_perm p, ls_func f where r.enabled = '1'  and ur.role_id=r.id and r.id=p.role_id and p.function_id=f.id and r.app_no = ? and f.app_no = ? and ur.user_id= ?";


	/** The Constant sqlForFindRolesByUser. */
	private static final String sqlForFindRolesByUser = "SELECT DISTINCT r.role_type as name FROM ls_usr_role ur ,ls_role r WHERE r.enabled ='1'  AND ur.role_id=r.id AND r.app_no =? AND ur.user_id= ? ";

	
	/* (non-Javadoc)
	 * @see com.legendshop.business.dao.security.AdminAuthDao#loadUserByUsername(java.lang.String)
	 */
	@Override
	public UserEntity loadUserByUsername(String username) {
		// 获取用户信息
		UserEntity user =  findAdminUserByName(username);
		if (user == null) {
			log.debug("Can not find user by name {}", username);
		}
		return user;
	}

	/**
	 * 管理员登录，如果密码不正确则不返回信息
	 * 带上用户权限和角色.
	 *
	 * @param username the username
	 * @param presentedPassword the presented password
	 * @return the user entity
	 */
	@Override
	public UserEntity loadAdminUserByUsername(String username, String presentedPassword) {
		// 获取用户信息
		UserEntity user =  findAdminUserByName(username);
		if (user == null) {
			log.debug("Can not find user by name {}", username);
			return null;
		}
		boolean isValid = additionalAuthenticationChecks(user, presentedPassword);
		if(!isValid){
			log.debug("User {} password is not valid", user.getName());
			return null;
		}
		List<GrantedAuthority> roles = findRolesByUser(user.getId(), ApplicationEnum.BACK_END.value());
		if (AppUtils.isBlank(roles)) {
			log.debug("User {}  has no roles", user.getName());
			return null;
		}
		user.setRoles(roles);
		
		user.setFunctions(findFunctionsByUser(user.getId(), ApplicationEnum.BACK_END.value()));//查找权限)
		//返回用户
		return user;
	}
	
	/**
	 * 找到有效时间内的用户.
	 *
	 * @param name the name
	 * @return the user entity
	 */
	protected UserEntity findAdminUserByName(String name) {
		List<UserEntity> userList = genericJdbcDao.query(sqlForFindAdminUserByName, new Object[] {name}, new RowMapper<UserEntity>() {
			public UserEntity mapRow(ResultSet rs, int index) throws SQLException {
				Date activeTime = rs.getDate("activeTime");
				if(activeTime != null && activeTime.before(new Date())){
					return null;
				}else{
					UserEntity user = new UserEntity();
					user.setEnabled(rs.getString("enabled"));
					user.setId(rs.getLong("id"));
					user.setName(rs.getString("name"));
					user.setRealName(rs.getString("realName"));
					user.setNote(rs.getString("note"));
					user.setPassword(rs.getString("password"));
					user.setPassChangeDate(rs.getTimestamp("passChangeDate"));
					user.setActiveTime(rs.getTimestamp("activeTime"));
					user.setChangePass(rs.getInt("changePass"));
					return user;
				}
			}
		});
		
		if (AppUtils.isNotBlank(userList)) {
			return userList.iterator().next();
		} else {
			return null;
		}
	}
	
	
	
	/**
	 * 检查用户名密码.
	 *
	 * @param userDetails the user details
	 * @param presentedPassword the presented password
	 * @return true, if additional authentication checks
	 */
	private boolean additionalAuthenticationChecks(UserEntity userDetails, String presentedPassword){
	        Object salt = null;
	        if (this.saltSource != null) {
	            salt = this.saltSource.getSalt(userDetails.getName());
	        }
	        return passwordEncoder.isPasswordValid(userDetails.getPassword(), presentedPassword, salt);
	}
	
	
	/**
	 * Find functions by user.
	 *
	 * @param userId the user id
	 * @param appNo the app no
	 * @return the list< granted function>
	 */
	private List<GrantedFunction> findFunctionsByUser(Long userId, String appNo) {
		return genericJdbcDao.query(sqlForFindFunctionsByUser, new Object[] { appNo, appNo, userId }, new RowMapper<GrantedFunction>() {
			public GrantedFunction mapRow(ResultSet rs, int index) throws SQLException {
				return new GrantedFunctionImpl(rs.getString("name"));
			}
		});
	}
	
	/**
	 * Find roles by user.
	 *
	 * @param userId the user id
	 * @param appNo the app no
	 * @return the list< granted authority>
	 */
	private List<GrantedAuthority> findRolesByUser(Long userId, String appNo) {
		return genericJdbcDao.query(sqlForFindRolesByUser, new Object[] { appNo, userId }, new RowMapper<GrantedAuthority>() {
			public GrantedAuthority mapRow(ResultSet rs, int index) throws SQLException {
				return new SimpleGrantedAuthority(rs.getString("name"));
			}
		});
	}

	/**
	 * Sets the password encoder.
	 *
	 * @param passwordEncoder the password encoder
	 */
	public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
		this.passwordEncoder = passwordEncoder;
	}

	/**
	 * Sets the salt source.
	 *
	 * @param saltSource the salt source
	 */
	public void setSaltSource(UserSaltSource saltSource) {
		this.saltSource = saltSource;
	}

	/**
	 * Sets the generic jdbc dao.
	 *
	 * @param genericJdbcDao the generic jdbc dao
	 */
	public void setGenericJdbcDao(GenericJdbcDao genericJdbcDao) {
		this.genericJdbcDao = genericJdbcDao;
	}
	

}
